[初心者向け] Next.js で初めての OpenAI API アプリを作ってみた(Tailwind CSS、Docker 利用)
こんにちは、アノテーション テクニカルサポートの Shimizu です。
昨今の OpenAI ブームに乗り、私も何かを始めてみたくなりました。
そこで、ちょうど勉強中だったフロントエンド開発環境(Next.js + Tailwind CSS + Docker)と OpenAI API を利用して、AI が質問に答えてくれるだけのシンプルな入門アプリを、実作業 30 分ほどで作ってみました。
ここでは筆者の備忘も兼ねて、一連の手順を記事にしてみました。
以下のような方の参考になれば幸いです。
- OpenAI API で最小限の動くアプリを作り、仕組みを理解したい
- Next.js(React)や Tailwind CSS などフロントエンドの流行りのフレームワークに触れてみたい
それでは、いってみましょう!
step1. 事前準備
まず、事前に下記を用意しましょう。
(1) OpenAI のアカウント登録、API シークレットキーの取得
筆者は下記のサイトを参考にさせていただきました。
OpenAI | APIキーを取得する方法 | ONE NOTES
※ なお API キーの取得は無料ですが、API の使用は有料です。
アカウント登録時に $18 分のクレジットが付与されるため、その範囲内なら無料で使用できますが、それを超えると課金対象となることに注意しましょう。
(2) PC 上で Docker コマンドを実行できる環境
筆者の場合は Windows の WSL2(Ubuntu)上で Docker を動かしています。
詳しい手順は下記の記事を参考にしてください。
Rancher Desktopをインストールしてみた | DevelopersIO
上記(1)(2)の用意ができたら、次のステップに進みましょう。
step2. Docker コンテナを起動し Next.js のプロジェクトを作成する
まずは作業PCのターミナルから下記のコマンドを実行し、Alpine Linux のコンテナを起動します。
# コンテナを起動 docker run --name nextjs-test -p 3000:3000 -itd alpine /bin/sh # 起動したコンテナのIDを確認し、コンテナ内にログインする docker ps -a docker exec -it コンテナ ID /bin/sh
ここから先はコンテナ内で node.js をインストールし、Next.js のプロジェクトを作成していきます。
※そのままターミナルで操作してもよいですが、すでに VSCode を導入済みの場合は下記リンクを参考に、VSCodeからコンテナに接続してターミナルで操作すると便利です。
既存のDocker開発環境をVS CodeのRemote Developmentで開発できるようにしてみた | DevelopersIO
いずれかの方法でコンテナ内にログインし、下記を実行します。
# 作業ディレクトリ /app を作成して移動する mkdir /app cd /app # node.js と npm をインストールし、バージョン確認する #(本記事の執筆時点では nodejs v18.14.2 / npm 9.1.2) apk add --no-cache nodejs apk add --update nodejs npm node -v npm -v # Next.js プロジェクトの作成 npx create-next-app
Next.js プロジェクトの作成時にオプションの入力を促されますが、筆者は下記のように設定しました。
特に変更の必要がなければ、同じ設定にして進みましょう。
✔ What is your project named? … my-nextjs-pj01 ✔ Would you like to use TypeScript with this project? … No ✔ Would you like to use ESLint with this project? … No ✔ Would you like to use `src/` directory with this project? … Yes ✔ Would you like to use experimental `app/` directory with this project? … No ? What import alias would you like configured? › 入力せずに進む
Next.js プロジェクトの作成が完了したら、下記を実施します。
# 作成したプロジェクトのディレクトリに移動 cd my-nextjs-pj01 # js から API 通信を行うためのパッケージをインストール npm install axios # 開発サーバーの起動 npm run dev
しばらく待って開発サーバーが起動したら、ブラウザで http://localhost:3000 にアクセスしてみましょう。 下記のような Next.js プロジェクトの初期ページが表示されるはずです。
それでは次のステップでは Next.js プロジェクトの初期ページを編集して、実際に OpenAI に接続するアプリを作成していきます。
step3. OpenAI アプリの作成と動作確認(サンプルコードあり)
Next.js の初期ページはプロジェクトフォルダ内の「src > pages > index.js」になります。
下記のサンプルコード1を丸ごとコピーして index.js に貼り付け、12行目の const API_KEY =
の部分のみ実際に取得した OpenAPI のシークレットキーに置き換えましょう。
※注意:OpenAI の API シークレットキーは、外部に公開しないようにしましょう!
今回はローカル環境でのテストのみのためコードに直接キーを記述していますが、作成したアプリを外部公開したり Git にコードを push する場合は必ず API キーを削除して環境変数へ格納するなどの実装をしましょう。
サンプルコード1: index.js の内容
import { useState } from "react"; import Head from 'next/head' import axios from "axios"; export default function Form() { const [prompt, setPrompt] = useState(""); const [model, setModel] = useState("text-davinci-002"); const [response, setResponse] = useState(""); const handleSubmit = async (e) => { e.preventDefault(); const API_KEY = '前準備で取得した OpenAI の APIキー'; const URL = "https://api.openai.com/v1/engines/" + model + "/completions"; try { const response = await axios.post( URL, { prompt: prompt, max_tokens: 200 }, { headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}`, }, } ); setResponse(response.data.choices[0].text); } catch (error) { console.log(error); } }; return ( <div> <Head> <title>Next.js で作る初めての OpenAI アプリ</title> <meta name="description" content="AI がどんな質問にも答えます" /> </Head> <h1>Next.js で作る初めての OpenAI アプリ</h1> <h2>質問:</h2> <form onSubmit={handleSubmit}> <p>Prompt:</p> <textarea placeholder="質問してください" value={prompt} onChange={(e) => setPrompt(e.target.value)} /> <p>Model:</p> <select value={model} onChange={(e) => setModel(e.target.value)}> <option value="text-davinci-002">Davinci</option> <option value="text-davinci-001">Davinci-codex</option> <option value="text-curie-001">Curie</option> <option value="text-babbage-001">Babbage</option> <option value="text-ada-001">Ada</option> </select> <br /> <button type="submit">質問する</button> </form> <h2>答え:</h2> <p>{response}</p> </div> ); }
index.js に上記の内容を貼り付けて保存すると自動でブラウザのリロードがかかり、表示された Next.js の初期ページが切り替わるはずです。
(自動で切り替わらない場合は、F5 キー等で手動リロードを試行しましょう)
実はこれだけで、OpenAI に接続する準備は完了です。
「Prompt」の欄に質問文を入れて「質問する」ボタンをクリックし、「答え:」の欄に AI からの回答が返ってくることを確認しましょう。
(うまく動作しない場合は、しばらく待って再試行するか、API キーの間違い等を確認してみてください)
なお「Model」は、AI の人格のようなものです。
同じ質問でも Model を変更して再度質問することで、回答が変わることを確認してみましょう。
これで、OpenAI API を利用した最小限のアプリが作れました!
なおここでは詳しく触れませんが、OpenAI API にはモデル選択の他にも、AI 回答の精度や方向性を定義するさまざまなパラメータが存在します。 コードを少し追加すれば、これらのパラメータを細かく調整して AI からの回答を得ることもできます。
もし興味があれば、下記の記事でどのようなパラメータがあるか確認してみてください。
OpenAI Playground を試してみた | DevelopersIO
それでは次のステップでは、Next.js にCSSフレームワーク「Tailwind CSS」を導入して、よりアプリらしい見た目に整えてみます。
step4. Tailwind CSS を利用して見栄えをよくする(サンプルコードあり)
まずターミナルで ctrl + c キーを押して開発サーバーを停止し、Next.js に Tailwind CSS のプラグインを導入します。 下記の公式ドキュメントの通りに進めます。
Install Tailwind CSS with Next.js - Tailwind CSS
# ターミナルで下記のコマンドを実行 npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
上記コマンドを実行すると、Next.js プロジェクトフォルダの直下に tailwind.config.js ファイルが生成されるので、下記の内容で上書きします。
tailwind.config.js の内容:
/** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./app/**/*.{js,ts,jsx,tsx}", "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", // Or if using `src` directory: "./src/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], }
併せて、globals.css ファイル(デフォルト設定なら src > styles フォルダの配下にあります)の先頭に、下記の 3 行を追記します。
globals.css の先頭に追記:
@tailwind base; @tailwind components; @tailwind utilities;
以上で Tailwind CSS を使用するための準備は完了です。
それでは先ほど作成したアプリに Tailwind CSS を適用して、見栄えを良くしてみます。
下記のサイトに Tailwind CSS でスタイリングされたフォームのUIが用意されているので、そこから必要なパーツを持ってきます。
Form Layouts - Official Tailwind CSS UI Components
下記の画面のように「Code : React」を選択すると、React 用のコードが取得できます。
Tailwind CSS の特徴であるクラス名の記述(className=""
の部分)が呪文のように長いため、最初はどこをどのように変えればよいか分かりにくいと思います。
今回は筆者が見栄えを整えたサンプルコードを記載しますので、そのままコピーして先ほどの index.js に貼り付けてみてください。
(先ほどと同様、const API_KEY =
の部分は実際の API キーに置き換えます)
サンプルコード2: index.js の内容(Tailwind CSS 適用)
import { useState } from "react"; import Head from 'next/head' import axios from "axios"; export default function Form() { const [prompt, setPrompt] = useState(""); const [model, setModel] = useState("text-davinci-002"); const [response, setResponse] = useState(""); const handleSubmit = async (e) => { e.preventDefault(); const API_KEY = '前準備で取得した OpenAI の APIキー'; const URL = "https://api.openai.com/v1/engines/" + model + "/completions"; try { const response = await axios.post( URL, { prompt: prompt, max_tokens: 200 }, { headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}`, }, } ); setResponse(response.data.choices[0].text); } catch (error) { console.log(error); } }; return ( <div> <Head> <title>Next.js で作る初めての OpenAI アプリ</title> <meta name="description" content="AI がどんな質問にも答えます" /> </Head> <h1 className="text-3xl font-bold leading-3 text-gray-900 m-5">Next.js で作る初めての OpenAI アプリ</h1> <div className="md:grid md:grid-cols-3 md:gap-6"> <div className="mt-5 p-4 md:col-span-2 md:mt-0"> <form onSubmit={handleSubmit}> <div className="shadow sm:overflow-hidden sm:rounded-md"> <div className="space-y-6 bg-white px-4 py-5 sm:p-6"> <div> <label htmlFor="Prompt" className="block text-sm font-medium leading-6 text-gray-900"> 質問文 </label> <div className="mt-2"> <textarea rows={3} className="mt-1 px-2 block w-full rounded-md border-0 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:py-1.5 sm:text-sm sm:leading-6" placeholder="ここに質問を入れてください" value={prompt} onChange={(e) => setPrompt(e.target.value)} /> </div> </div> <div className="col-span-6 sm:col-span-3"> <label htmlFor="model" className="block text-sm font-medium leading-6 text-gray-900"> モデルを選ぶ </label> <select className="mt-2 block w-full rounded-md border-0 bg-white py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" value={model} onChange={(e) => setModel(e.target.value)} > <option value="text-davinci-002">Davinci</option> <option value="text-davinci-001">Davinci-codex</option> <option value="text-curie-001">Curie</option> <option value="text-babbage-001">Babbage</option> <option value="text-ada-001">Ada</option> </select> </div> </div> <div className="bg-gray-50 px-4 py-3 sm:px-6"> <button type="submit" className="inline-flex justify-center rounded-md bg-indigo-600 py-2 px-3 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500" > 質問する </button> </div> </div> </form> </div> <div className="mt-4 mr-4 shadow sm:overflow-hidden sm:rounded-md"> <div className="bg-white px-4 py-5 sm:p-6"> <h2 className="text-base font-semibold leading-6 text-gray-900">質問の答え</h2> <p className="mt-1 text-sm text-gray-600">{response}</p> </div> </div> </div> </div> ); }
index.js を上記の内容に置き換えたら、再度ターミナルから npm run dev を実行して開発サーバーを起動し、ブラウザで http://localhost:3000 にアクセスしてみましょう。
すると、先ほどと同じアプリですがより見栄えが洗練され、アプリらしくなったことが確認できます。
これで、Next.js を使った最初の OpenAI アプリが完成しました。
お疲れさまでした!
さいごに
いかがでしたでしょうか。
今回は最短で OpenAI API の仕組みを理解するためのシンプルなアプリですが、アイデア次第で色々と面白いものが作れそうです。
筆者も今後さらに高度で実用的なアプリ作りにチャレンジし、また機会があれば記事にしたいと思います。
この記事が皆様の OpenAI アプリ開発を始める一助となれば幸いです!